use serde::{Serialize, Deserialize};
use bincode::{ErrorKind};
use sha1::Sha1;
use once_cell::sync::OnceCell;
use std::sync::RwLock;

pub const HEADER_SIZE: usize = 2 + 4 + 1 + 1 + 4 + 4 + 20 + 8;
pub static  sha1_obj:  OnceCell<RwLock<Sha1>> = OnceCell::new();

#[derive(Serialize, Deserialize, Debug)]
pub struct ProtoHeader {
    pub szHeaderFlag: [char; 2],
    pub nProtoID: i32,
    pub nProtoFmtType: u8,
    pub nProtoVer: u8,
    pub nSerialNo: i32,
    pub nBodyLen: i32,
    pub arrBodySHA1: [u8; 20],
    pub arrReserved: [u8; 8],
}

impl ProtoHeader {
    pub fn init() {
        sha1_obj.set(RwLock::new(sha1::Sha1::new()));
    }

    pub fn new(protoId: i32, body: &[u8], serialNo: i32) -> ProtoHeader {
        // let sha1_obj: &mut Sha1 = &mut sha1::Sha1::new();
        let mut sha1 = sha1_obj.get().unwrap().write().unwrap();
        sha1.update(body);
        return ProtoHeader {
            szHeaderFlag: ['F', 'T'],
            nProtoID: protoId,
            nProtoFmtType: 0,
            nProtoVer: 0,
            nSerialNo: serialNo,
            nBodyLen: body.len() as i32,
            arrBodySHA1: sha1.digest().bytes(),
            arrReserved: [0; 8],
        };
    }

    pub fn parse(data: &[u8], offset: usize) -> bincode::Result<ProtoHeader> {
        if offset + HEADER_SIZE > data.len() {
            return Err(Box::new(ErrorKind::Custom("offset + HEADER_SIZE > data.length".to_string())));
        }

        bincode::deserialize(&data[offset..offset + HEADER_SIZE])
    }

    pub fn write(&self) -> bincode::Result<Vec<u8>> {
        // if dst.len() < HEADER_SIZE {
        //     return Err(Box::new(ErrorKind::Custom("dst.len() < HEADER_SIZE".to_string())));
        // }
        bincode::serialize(self)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde::{Serialize, Deserialize};
    use crate::protos::qot_get_kl;
    use prost::Message;
    use crate::protos::qot_common::Security;

    #[test]
    fn test_serilize() {
        let tt = qot_get_kl::Response {
            ret_type: 1,
            ret_msg: Some("Nonesf发放".to_string()),
            err_code: Some(1),
            s2c: Some(qot_get_kl::S2c { security: Security { market: 1, code: "ss范德萨".to_string() }, kl_list: vec![] }),
        };
        let mut buf = vec![];
        tt.encode(&mut buf).unwrap();

        let decoded: qot_get_kl::Response = Message::decode(&buf[..]).unwrap();
        // println!("serialized: {:?}\noriginal: {:?}", buf, decoded)
    }
}